package com.zhuangfei.timetable.view;

import com.zhuangfei.timetable.model.Schedule;
import com.zhuangfei.timetable.model.ScheduleEnable;
import com.zhuangfei.timetable.model.ScheduleSupport;
import com.zhuangfei.timetable.utils.ScreenUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * 周次选择栏的每项自定义View,表示某周的有课情况.
 * 使用周一至周五、第1-10节的数据进行绘制,绘制的结果是一个5x5的点阵：
 * <p>
 * 5列分别表示周一至周五
 * 5行分别表示1-2节、3-4节、5-6节、7-8节、9-10节的有课情况
 * <p>
 * 有课的地方用亮色的圆点，没课的地方用暗色的圆点
 */

public class PerWeekView extends Component implements Component.DrawTask {

    private final String RADIUS = "radius"; // 圆点半径
    private final String LIGHT_COLOR = "light_color"; // 亮色
    private final String GRAY_COLOR = "gray_color"; // 暗色

    private static final String TAG = "PerWeekView";

    // 控件宽度
    private int width;

    // 圆点半径
    private int radius;

    // 亮色画笔
    private Paint lightPaint;

    // 暗色画笔
    private Paint grayPaint;

    // 亮色
    private int lightColor;

    // 暗色
    private int grayColor;

    // 数据源
    private List<Schedule> dataSource;

    /**
     * 获取亮色的画笔
     *
     * @return 亮色的画笔
     */
    public Paint getLightPaint() {
        return lightPaint;
    }

    /**
     * 获取暗色的画笔
     *
     * @return 暗色的画笔
     */
    public Paint getGrayPaint() {
        return grayPaint;
    }

    /**
     * 设置亮色
     *
     * @param lightARGBColor 亮色
     * @return PerWeekView控件自身
     */
    public PerWeekView setLightColor(int lightARGBColor) {
        this.lightColor = lightColor;
        invalidate();
        return this;
    }

    /**
     * 设置暗色
     *
     * @param grayARGBColor 暗色
     * @return PerWeekView控件自身
     */
    public PerWeekView setGrayColor(int grayARGBColor) {
        this.grayColor = grayColor;
        invalidate();
        return this;
    }

    /**
     * 获取数据源
     *
     * @return 数据源
     */
    public List<Schedule> getDataSource() {
        if (dataSource == null) {
            dataSource = new ArrayList<>();
        }
        return dataSource;
    }

    /**
     * 设置数据源
     *
     * @param list    数据源
     * @param curWeek 当前周
     * @return PerWeekView控件自身
     */
    public PerWeekView setSource(List<? extends ScheduleEnable> list, int curWeek) {
        if (list == null) {
            return this;
        }
        setData(ScheduleSupport.transform(list), curWeek);
        return this;
    }

    /**
     * 设置数据源
     *
     * @param list    数据源
     * @param curWeek 当前周
     * @return PerWeekView控件自身
     */
    public PerWeekView setData(List<Schedule> list, int curWeek) {
        if (list == null) {
            return this;
        }
        getDataSource().clear();
        for (int i = 0; i < list.size(); i++) {
            Schedule schedule = list.get(i);
            if (ScheduleSupport.isThisWeek(schedule, curWeek) && schedule.getStart() <= 10 && schedule.getDay() <= 5) {
                getDataSource().add(schedule);
            }
        }
        invalidate();
        return this;
    }

    /**
     * 设置半径Px
     *
     * @param radiusPx 半径
     * @return PerWeekView控件自身
     */
    public PerWeekView setRadiusInPx(int radiusPx) {
        this.radius = radius;
        return this;
    }

    /**
     * 设置半径Vp
     *
     * @param radiusVp 半径
     * @return PerWeekView控件自身
     */
    public PerWeekView setRadiusInVp(int radiusVp) {
        setRadiusInPx(ScreenUtils.vp2px(getContext(), radiusVp));
        return this;
    }

    public PerWeekView(Context context) {
        this(context, null);
    }

    public PerWeekView(Context context, AttrSet attrs) {
        super(context, attrs);
        initAttr(attrs);

        lightPaint = new Paint();
        lightPaint.setColor(new Color(lightColor));
        lightPaint.setAntiAlias(true);
        lightPaint.setStyle(Paint.Style.FILL_STYLE);

        grayPaint = new Paint();
        grayPaint.setColor(new Color(grayColor));
        grayPaint.setAntiAlias(true);
        grayPaint.setStyle(Paint.Style.FILL_STYLE);
        addDrawTask(this);
    }

    private void initAttr(AttrSet attrs) {
        int defRadius = ScreenUtils.vp2px(getContext(), 2);
        grayColor = Color.rgb(207, 219, 219);
        if (attrs.getAttr(GRAY_COLOR).isPresent()) {
            grayColor = attrs.getAttr(GRAY_COLOR).get().getColorValue().getValue();
        }
        lightColor = 0xff3FCAB8;
        if (attrs.getAttr(LIGHT_COLOR).isPresent()) {
            grayColor = attrs.getAttr(LIGHT_COLOR).get().getColorValue().getValue();
        }
        radius = defRadius;
        if (attrs.getAttr(RADIUS).isPresent()) {
            radius = attrs.getAttr(RADIUS).get().getDimensionValue();
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        width = getWidth();
        int mar = (width - 10 * radius) / 6;
        lightPaint.setColor(new Color(lightColor));
        grayPaint.setColor(new Color(grayColor));

        int[][] tmp = getArray();

        // 绘制点
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (tmp[i][j] == 0) {
                    drawPoint(canvas, mar + radius + (mar + 2 * radius) * j, mar + radius + (mar + 2 * radius) * i, radius, grayPaint);
                } else {
                    drawPoint(canvas, mar + radius + (mar + 2 * radius) * j, mar + radius + (mar + 2 * radius) * i, radius, lightPaint);
                }
            }
        }
    }

    /**
     * 根据此数据源分析出一个二维数组
     *
     * @return 数据源二维数组
     */
    public int[][] getArray() {
        int[][] arr = new int[10][5];
        int[][] tmp = new int[5][5];

        // 初始化数组
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 5; j++) {
                arr[i][j] = 0;
            }
        }

        // 标记上课的位置
        // 遍历课程集合，将在某课程的上课区间的位置都标记上
        int start;
        int end;
        for (int i = 0; i < getDataSource().size(); i++) {
            Schedule schedule = getDataSource().get(i);
            start = schedule.getStart();
            end = schedule.getStart() + schedule.getStep() - 1;
            if (end > 10) {
                end = 10;
            }

            // 标记区间的所有位置
            for (int m = start; m <= end; m++) {
                arr[m - 1][schedule.getDay() - 1] = 1;
            }
        }

        // 合并分组标记
        // 用到了10小节的数据来标记
        // 10小节被分为了5组分别来表示5行的上课状态
        // 每个分组中只要有一个有课，那么该组对外的状态应该为有课
        int t = 0;
        for (int i = 0; i < 10; i += 2) {
            for (int j = 0; j < 5; j++) {
                if (arr[i][j] == 0 && arr[i + 1][j] == 0) {
                    tmp[t][j] = 0;
                } else {
                    tmp[t][j] = 1;
                }
            }
            t++;
        }
        return tmp;
    }

    /**
     * 画点
     *
     * @param canvas 画布
     * @param x      圆心x
     * @param y      圆心y
     * @param radius 半径
     * @param p      画笔
     */
    public void drawPoint(Canvas canvas, int x, int y, int radius, Paint p) {
        canvas.drawCircle(x, y, radius, p);
    }
}
